package com.efamily.ewallet.client.expense.widget;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.efamily.ewallet.client.MainWidget;
import com.efamily.ewallet.client.account.bean.AccountBean;
import com.efamily.ewallet.client.common.CustomEvents;
import com.efamily.ewallet.client.common.CustomEventType;
import com.efamily.ewallet.client.common.DefaultAsyncCallback;
import com.efamily.ewallet.client.common.DifferentItemsSummaryRenderer;
import com.efamily.ewallet.client.common.SelectedBalanceItemEvent;
import com.efamily.ewallet.client.expense.bean.ExpenseBean;
import com.efamily.ewallet.client.expense.bean.ExpenseSearchConfig;
import com.efamily.ewallet.client.expense.service.ExpenseServiceAsync;
import com.extjs.gxt.ui.client.Style.IconAlign;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.PagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.store.GroupingStore;
import com.extjs.gxt.ui.client.widget.Composite;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridGroupRenderer;
import com.extjs.gxt.ui.client.widget.grid.GroupColumnData;
import com.extjs.gxt.ui.client.widget.grid.GroupSummaryView;
import com.extjs.gxt.ui.client.widget.grid.SummaryColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.SummaryRenderer;
import com.extjs.gxt.ui.client.widget.grid.SummaryType;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;
import com.extjs.gxt.ui.client.widget.toolbar.SeparatorToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;

public class ExpenseGridWidget extends Composite {
	private Grid<ExpenseBean> grid;
	private final ExpenseServiceAsync expenseService = ExpenseServiceAsync.instance;
	private ExpenseSearchConfig searchConfig;
	private int rowCount = 40;
	private ContentPanel contentPanel = new ContentPanel();
	private AddEditExpenseWindow addEditExpenseWnd = new AddEditExpenseWindow();
	private AccountBean accountBean = new AccountBean();

	public ExpenseGridWidget(AccountBean accountBean) {
		this.accountBean = accountBean;
		buildGrid();
		Dispatcher.get().addListener(
				CustomEvents.ADD_EXPENSE.getEventType(),
				new Listener<BaseEvent>() {
					public void handleEvent(BaseEvent be) {
						try {
							grid.getStore().getLoader().load();
						} catch (Exception ex) {
							MessageBox.alert("Operation failed",
									"Exception was thrown within add/edit operation. "
											+ ex.getMessage(), null);
							ex.printStackTrace();
						}
					}
				});
		
		Dispatcher.get().addListener(
				CustomEvents.SELECTED_BALANCE_ITEMS.getEventType(),
				new Listener<SelectedBalanceItemEvent>() {
					public void handleEvent(SelectedBalanceItemEvent baseEvent) {
						List<Date> balanceDates = baseEvent.getBalanceDates();
						grid.getStore().getLoader().load();
						//TODO warning
						if (balanceDates != null && balanceDates.size() > 0) {
							searchConfig = new ExpenseSearchConfig(baseEvent
									.getDetailedBy(), balanceDates);
							grid.getStore().getLoader().load();
						} else {
							searchConfig = null;
						}
					}
				});
		initComponent(contentPanel);
	}

	private void buildGrid() {
		RpcProxy<PagingLoadResult<ExpenseBean>> proxy = new RpcProxy<PagingLoadResult<ExpenseBean>>() {
			@Override
			protected void load(Object loadConfig,
					AsyncCallback<PagingLoadResult<ExpenseBean>> callback) {
				expenseService.getExpenses(accountBean, searchConfig,
						(PagingLoadConfig) loadConfig, callback);
			}
		};

		PagingLoader<PagingLoadResult<ExpenseBean>> loader = new BasePagingLoader<PagingLoadResult<ExpenseBean>>(
				proxy);
		loader.setRemoteSort(true);
		PagingToolBar pagingToolBar = new PagingToolBar(rowCount);
		pagingToolBar.bind(loader);
		contentPanel.setBottomComponent(pagingToolBar);
		GroupingStore<ExpenseBean> store = new GroupingStore<ExpenseBean>(
				loader);

		store.groupBy("expense_date");
		List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
		SummaryColumnConfig<Integer> id = new SummaryColumnConfig<Integer>(
				"id", "Identifier", 55);
		id.setHidden(true);
		id.setGroupable(false);
		SummaryColumnConfig<Integer> expenseName = new SummaryColumnConfig<Integer>(
				"name", "Expense", 80);
		expenseName.setSummaryType(SummaryType.COUNT);
		expenseName.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {

				return value.intValue() > 1 ? "(" + value.intValue()
						+ " Expenses)" : "(1 Expense)";
			}
		});
		SummaryColumnConfig<Integer> type = new SummaryColumnConfig<Integer>(
				"type", "Type", 80);
		type.setSummaryType(new DifferentItemsSummaryRenderer());
		type.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(" + value.intValue()
						+ " Types)" : "(1 Type)";
			}
		});
		SummaryColumnConfig<Integer> category = new SummaryColumnConfig<Integer>(
				"category", "Category", 80);
		category.setSummaryType(new DifferentItemsSummaryRenderer());
		category.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(In " + value.intValue()
						+ " Categories)" : "(In 1 Category)";
			}
		});
		SummaryColumnConfig<Integer> weekDay = new SummaryColumnConfig<Integer>(
				"week_day", "Day", 80);
		// weekDay.setHidden(true);
		weekDay.setSummaryType(new DifferentItemsSummaryRenderer());
		weekDay.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(In" + value.intValue()
						+ " Days)" : "(In 1 Day)";
			}
		});
		SummaryColumnConfig<Integer> monthDay = new SummaryColumnConfig<Integer>(
				"month_day", "Days Number", 80);
		// monthDay.setHidden(true);
		monthDay.setSummaryType(new DifferentItemsSummaryRenderer());
		monthDay.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(In " + value.intValue()
						+ " Days of month)" : "(In 1 Day of month)";
			}
		});
		SummaryColumnConfig<Integer> month = new SummaryColumnConfig<Integer>(
				"month", "Month", 80);
		// month.setHidden(true);
		month.setSummaryType(new DifferentItemsSummaryRenderer());
		month.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(In " + value.intValue()
						+ " Monthes)" : "(In 1 Month)";
			}
		});
		SummaryColumnConfig<Integer> year = new SummaryColumnConfig<Integer>(
				"year", "Year", 80);
		// year.setHidden(true);
		year.setSummaryType(new DifferentItemsSummaryRenderer());
		year.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(In " + value.intValue()
						+ " Years)" : "(In 1 Year)";
			}
		});
		SummaryColumnConfig<Double> cost = new SummaryColumnConfig<Double>(
				"cost", "Cost", 80);
		// cost.setHidden(true);
		cost.setSummaryType(SummaryType.SUM);
		SummaryColumnConfig<Integer> expenseDate = new SummaryColumnConfig<Integer>(
				"expense_date", "Date", 80);
		// expenseDate.setHidden(true);
		expenseDate.setDateTimeFormat(DateTimeFormat.getFormat("dd/MM/y"));
		expenseDate.setSummaryType(new DifferentItemsSummaryRenderer());
		expenseDate.setSummaryRenderer(new SummaryRenderer() {
			public String render(Number value, Map<String, Number> data) {
				return value.intValue() > 1 ? "(" + value.intValue() + " Days)"
						: "(1 Day)";
			}
		});
		SummaryColumnConfig<Number> description = new SummaryColumnConfig<Number>(
				"description", "Description", 80);
		description.setGroupable(false);
		description.setSortable(false);
		columns.add(id);
		columns.add(expenseName);
		columns.add(weekDay);
		columns.add(monthDay);
		columns.add(month);
		columns.add(year);
		columns.add(expenseDate);
		columns.add(cost);
		columns.add(type);
		columns.add(description);
		columns.add(category);

		final ColumnModel cm = new ColumnModel(columns);

		GroupSummaryView view = new GroupSummaryView();
		view.setShowGroupedColumn(false);
		view.setForceFit(true);
		view.setGroupRenderer(new GridGroupRenderer() {
			public String render(GroupColumnData data) {
				String f = cm.getColumnById(data.field).getHeader();
				String l = data.models.size() == 1 ? "Item" : "Items";
				return f + ": " + data.group + " (" + data.models.size() + " "
						+ l + ")";
			}
		});

		contentPanel.setHeaderVisible(false);
		contentPanel.setLayout(new FitLayout());

		grid = new Grid<ExpenseBean>(store, cm);
		grid.setView(view);
		grid.setBorders(true);
		grid.setAutoExpandColumn("description");
		grid.setMinColumnWidth(40);
		grid.setStripeRows(true);
		contentPanel.add(grid);
		addToolbar();
	}

	private void addToolbar() {
		final ToolBar toolBar = new ToolBar();
		if (MainWidget.currentUser != null
				&& MainWidget.currentUser.getAccount().equals(accountBean)) {
			toolBar.setVisible(true);
		} else {
			toolBar.setVisible(false);
		}
		Button addBtn = new Button("&nbsp;Add");
		addBtn.setIconAlign(IconAlign.LEFT);
		addBtn.setIconStyle("icon-add");
		addBtn.addSelectionListener(new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				addEditExpenseWnd.showAddWindow(accountBean);
			}

		});
		toolBar.add(addBtn);
		toolBar.add(new SeparatorToolItem());
		final Button editBtn = new Button("&nbsp;Edit");
		editBtn.setIconStyle("icon-edit");
		editBtn.setIconAlign(IconAlign.LEFT);
		editBtn.setEnabled(false);
		editBtn.addSelectionListener(new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				ExpenseBean expense = grid.getSelectionModel()
						.getSelectedItem();
				addEditExpenseWnd.showEditWindow(accountBean, expense);
			}

		});

		toolBar.add(editBtn);
		toolBar.add(new SeparatorToolItem());
		final Button deleteBtn = new Button("&nbsp;Remove");
		deleteBtn.setIconAlign(IconAlign.LEFT);
		deleteBtn.setIconStyle("icon-delete");
		deleteBtn.setEnabled(false);
		deleteBtn.setEnabled(false);
		deleteBtn.addSelectionListener(new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				List<ExpenseBean> expenses = grid.getSelectionModel()
						.getSelectedItems();
				List<Integer> expensesID = new ArrayList<Integer>();
				for (ExpenseBean expense : expenses) {
					expensesID.add(expense.getId());
				}
				expenseService.deleteExpenses(accountBean, expensesID,
						new DefaultAsyncCallback<Boolean>() {
							@Override
							public void onSuccess(Boolean isDone) {
								if (isDone) {
									grid.getStore().getLoader().load();
								} else {
									MessageBox
											.alert(
													"Operation failed",
													"Some exception was thrown. Try again or ask administrator.",
													null);
								}
							}
						});
			}

		});
		toolBar.add(deleteBtn);
		contentPanel.setTopComponent(toolBar);

		grid.getSelectionModel().addSelectionChangedListener(
				new SelectionChangedListener<ExpenseBean>() {
					@Override
					public void selectionChanged(
							SelectionChangedEvent<ExpenseBean> se) {
						if (se.getSelection().size() == 0) {
							deleteBtn.setEnabled(false);
							editBtn.setEnabled(false);
						} else if (se.getSelection().size() == 1) {
							editBtn.setEnabled(true);
							deleteBtn.setEnabled(true);
						} else {
							editBtn.setEnabled(false);
							deleteBtn.setEnabled(true);
						}
					}
				});
		Dispatcher.get().addListener(
				CustomEvents.LOGED_IN.getEventType(),
				new Listener<BaseEvent>() {
					public void handleEvent(BaseEvent be) {
						if (MainWidget.currentUser != null
								&& MainWidget.currentUser.getAccount().equals(
										ExpenseGridWidget.this.accountBean)) {
							if (toolBar.isRendered()) {
								toolBar.show();
							} else {
								toolBar.setVisible(true);
							}
						}
					}
				});
		Dispatcher.get().addListener(
				CustomEvents.LOGED_OUT.getEventType(),
				new Listener<BaseEvent>() {
					public void handleEvent(BaseEvent be) {
						if (toolBar.isRendered()) {
							toolBar.hide();
						} else {
							toolBar.setVisible(false);
						}
					}
				});

	}

	@SuppressWarnings("unchecked")
	@Override
	protected void onLoad() {
		super.onLoad();
		((PagingLoader) grid.getStore().getLoader()).load(0, rowCount);
	}

	public int getRowCount() {
		return rowCount;
	}

	public void setRowCount(int rowCount) {
		this.rowCount = rowCount;
		((PagingToolBar) contentPanel.getBottomComponent())
				.setPageSize(rowCount);
	}

}